package model.datastructure;

import java.util.Arrays;

/**
 * 
 * @author
 */
public class FieldSurface2D extends AbstractSurface2D {

	private Field2D mField;
	/**
	 * Constructor, uses the field to create an array of the right size to save
	 * the surface in
	 * 
	 * @param field
	 */
	public FieldSurface2D( Field2D field ) {
		super( new Dimension1D( field.getDimension().getWidth()	) );
		mField = field;
		mSurface = calculateTopSurface();
	}

	/**
	 * Creates a new surface from the give array
	 * 
	 * @param surface
	 *            what the surface should look like
	 */
	public FieldSurface2D( int[] surface ) {
		super( new Dimension1D( surface.length ) );
		mSurface = surface;
	}

	/**
	 * Returns the surface, looking from the top of the field. Each position in
	 * the array denotes the number of empty y positions for that x position,
	 * looking from the top.
	 * 
	 * @return surface
	 */
	private int[] calculateTopSurface() {
		/* So we have something to fill in */
		int[] surface = new int[mField.getDimension().getWidth()];

		/* Loop through it left to right */
		boolean found;
		for( int indexX = 0; indexX < mField.getDimension().getWidth(); indexX ++ ) {

			/* Loop through it top to bottom */
			int indexY = mField.getDimension().getHeight() - 1;
			found = false;
			while( ! found && indexY >= 0 && mField.getDimension().getHeight() > 0 ) {

				/* There is a ( piece of ) block here! Better make a note of it */
				if( mField.getEmptyChar() != mField.getCharAt( indexX, indexY ) ) {

					/* Remember the current yPosition */
					surface[indexX] = indexY + 1;
					found = true;
				} else {
					indexY -- ;
				}
			}
		}

		/* There ya go */
		return surface;
	}

	/**
	 * Returns the blocksurface, added to a copy of this surface, together with
	 * the empty space blocked of by this placing
	 * 
	 * @param blockSurface
	 *            : the blocksurface that should be placed on top of this
	 *            fieldsurface
	 * @param x
	 *            : the x position on the fieldsurface that the blocksurface
	 *            should be placed at.
	 * @return A fit object containing the new surface and the empty space
	 *         created
	 */
	public Fit match( ISurface blockSurface, int x ) {
		BlockSurface2D surface = ( BlockSurface2D ) blockSurface;
		int[] newStructure = mSurface.clone();
		int[] emptySpace = new int[mDimension.getLength()];
		/*
		 * Find the highest place on the field, combined with the lowest place
		 * on the bottom of the block. This is the place it gets stuck on
		 */
		int stickyHeight = - 1;
		int stickyLow = Integer.MAX_VALUE;
		for( int i = 0; i < surface.getWidth(); i ++ ) {
			int total = mSurface[x + i] + surface.getHighest() - surface.getBottomSurface()[i];
			int lowest = mSurface[x + i];
			//int total = mSurface[x + i] + surface.getHighest();
			if( total > stickyHeight ) {
				stickyHeight = total;
			}
			if( lowest < stickyLow ) {
				stickyLow = lowest;
			}
		}
		
		/* Find the new high and empty space for each position */
		for( int i = 0; i < surface.getWidth(); i ++ ) {
			/*
			 * The height at this location is the highest location on the new
			 * surface (stickyHeight) - the topsurface
			 */
			//newStructure[x + i] = stickyHeight - surface.getTopSurface()[i] + surface.getHighest();
			newStructure[x + i] = stickyHeight - surface.getHighest() + surface.getTopSurface()[i];
			/*
			 * the empty space is the height that of the new surface, minus the
			 * height of the blocks that are "used"
			 */
			//emptySpace[x + i] = stickyHeight - surface.getBottomSurface()[i] - mSurface[x + i];
			emptySpace[x + i] = ( (stickyHeight - stickyLow) - (surface.getHighest() - surface.getBottomSurface()[i]) ) - (mSurface[x + i] - stickyLow) ; 
		}

		FieldSurface2D newSurface = new FieldSurface2D( newStructure );
		Fit result = new Fit( newSurface, emptySpace, stickyHeight - surface.getHighest() );

		return result;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "FieldSurface2D mSurface=" + Arrays.toString(mSurface) + "]";
	}
	
	public int getLowest() {
		int lowestY = Integer.MAX_VALUE;
		for (int i = 0; i < mSurface.length; i++){
			if (mSurface[i] < lowestY) {
				lowestY = mSurface[i];
			}
		}
		return lowestY;
	}

	public int getHighest() {
		int highestY = Integer.MIN_VALUE;
		for (int i = 0; i < mSurface.length; i++){
			if (mSurface[i] > highestY) {
				highestY = mSurface[i];
			}
		}
		return highestY;
	}
	
}